import {
  AxesHelper,
  Camera,
  EventDispatcher,
  GridHelper,
  Line,
  Object3D,
  Raycaster,
  Scene,
  Vector2,
} from "three";
import {
  TransformControlsGizmo,
  TransformControlsPlane,
} from "three/examples/jsm/controls/TransformControls";
import Base from "./Base";

export default class EventManger extends EventDispatcher {
  private base: Base;
  private raycaster: Raycaster = new Raycaster();
  private mouse: Vector2 = new Vector2();
  private dom: HTMLCanvasElement;
  private scene: Scene;
  private camera: Camera;
  constructor() {
    super();
    const base = Base.getInstance();
    this.base = base;

    this.dom = base.canvas;
    this.scene = base.scene;
    this.camera = base.cameras.perspectiveCamera;

    const mouse = this.mouse;
    const raycaster = this.raycaster;
    const dom = this.dom;

    let cacheObject: Object3D | null = null;

    dom.addEventListener("mousedown", (event) => {
      // 选取物体的操作
      raycaster.setFromCamera(mouse, this.camera);
      const intersection = raycaster.intersectObjects(this.scene.children);

      // 这里将事件派发到this上面,相当于注册全局事件,也就是将事件派发到EventManager的实例上面
      this.dispatchEvent({
        type: "mousedown",
        intersection,
      });

      if (intersection.length) {
        const object = intersection[0].object;
        // 派发事件到3d物体上面
        object.dispatchEvent({
          type: "mousedown",
        });
      }
    });

    dom.addEventListener("mousemove", (event) => {
      mouse.x = (event.offsetX / dom.offsetWidth) * 2 - 1;
      mouse.y = (-event.offsetY * 2) / dom.offsetHeight + 1;

      // 选取物体的操作
      raycaster.setFromCamera(mouse, this.camera);

      const intersection = raycaster.intersectObjects(this.scene.children);

      // 全局派发事件
      this.dispatchEvent({
        type: "mousemove",
        intersection,
      });

      if (intersection.length) {
        const object = intersection[0].object;

        if (object !== cacheObject) {
          if (cacheObject) {
            cacheObject.dispatchEvent({
              type: "mouseleave",
            });
          }
          object.dispatchEvent({
            type: "mouseenter",
          });
        } else if (object === cacheObject) {
          object.dispatchEvent({
            type: "mousemove",
          });
        }
        cacheObject = object;
      } else {
        if (cacheObject) {
          cacheObject.dispatchEvent({
            type: "mouseleave",
          });
        }
        cacheObject = null;
      }
    });

    dom.addEventListener("mouseup", (event) => {
      // 选取物体的操作
      raycaster.setFromCamera(mouse, this.camera);
      const intersection = raycaster.intersectObjects(this.scene.children);

      this.dispatchEvent({
        type: "mouseup",
        intersection,
      });
      if (intersection.length) {
        const object = intersection[0].object;
        object.dispatchEvent({
          type: "mouseup",
        });
      }
    });

    dom.addEventListener("click", (event) => {
      // 选取物体的操作
      raycaster.setFromCamera(mouse, this.camera);
      let intersections = raycaster.intersectObjects(this.scene.children);

      this.dispatchEvent({
        type: "click",
        intersections,
      });

      //移出变换控制器本身,并不想要其,会干扰
      this.scene.remove(...this.base.noTransfromControlObjs);
      intersections = raycaster.intersectObjects(this.scene.children);
      //使用完要给添加回去
      this.scene.add(...this.base.noTransfromControlObjs);

      const targetIntersection = intersections.filter((intersection) => {
        return (
          // 除了上面的移出添加方法,也可是使用过滤的方法,来过滤掉一些不需要的内容
          !(intersection.object instanceof TransformControlsPlane) &&
          !(intersection.object instanceof AxesHelper) &&
          !(intersection.object instanceof GridHelper) &&
          !(intersection.object instanceof Line) &&
          !(intersection.object.parent instanceof TransformControlsGizmo)
          //   !(intersection.object instanceof Line2) &&
        );
      });

      if (targetIntersection.length) {
        const object = targetIntersection[0].object;

        console.log(object);

        object.dispatchEvent({
          type: "click",
        });
      }
    });
  }
}
